package one.stand.service.user;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import one.stand.code.RedisCode;
import one.stand.entity.TokenEntity;
import one.stand.enums.LoginEnum;
import one.stand.util.RandomUtil;
import one.stand.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author cjr
 */
@Service
@Slf4j
public class TokenServiceImpl implements TokenService {
    /**
     * 缓存3天
     */
    private final static Integer LOGIN_TIME_LONG = 60 * 60 * 24 * 3;
    private final static TimeUnit TIME_UNIT = TimeUnit.SECONDS;

    private final static String TOKEN_SPLIT = "_";
    private final static String TOKEN_LIKE = "*_";

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public void save(TokenEntity tokenEntity) {
        tokenEntity.setToken(RandomUtil.generateString(10) + TOKEN_SPLIT + tokenEntity.getId());
        tokenEntity.setLogintime(new Date());
        log.info("登录缓存信息：{}", JSON.toJSONString(tokenEntity));
        String tokenKey = RedisCode.getUserLoginToken(tokenEntity.getToken());
        redisUtil.set(tokenKey, tokenEntity, LOGIN_TIME_LONG, TIME_UNIT);
        boolean result = redisUtil.set(RedisCode.getTokenToUser(tokenEntity.getId().intValue(), tokenEntity.getLoginProgramName()), tokenKey, LOGIN_TIME_LONG, TIME_UNIT);
        Assert.isTrue(result, "生成token失败");

        //记录登录状态
        saveLoginStatus(tokenEntity.getId().intValue(), tokenEntity.getLoginProgramName());
    }

    @Override
    public void saveAdmin(TokenEntity tokenEntity) {
        tokenEntity.setToken(RandomUtil.generateString(10) + TOKEN_SPLIT + tokenEntity.getId());
        tokenEntity.setLogintime(new Date());
        boolean result = redisUtil.set(RedisCode.getAdminToken(tokenEntity.getToken()), tokenEntity, LOGIN_TIME_LONG, TIME_UNIT);
        Assert.isTrue(result, "生成token失败");
    }

    @Override
    public void saveLoginStatus(Integer userId, String loginEnum) {
        String loginStatusKey = RedisCode.getUserLoginStatus(userId, loginEnum);
        redisUtil.set(loginStatusKey, LOGIN_ONLINE);
    }

    @Override
    public void remove(Integer userId, LoginEnum loginEnum) {
        String key = RedisCode.getTokenToUser(userId, loginEnum.getCode());
        String tokenKey = redisUtil.get(key);
        if (Objects.nonNull(tokenKey)) {
            redisUtil.remove(tokenKey);
        }
    }

    @Override
    public void remove(List<Long> userIds) {
        Set<String> keyList = new HashSet<>();
        for (Long userId : userIds) {
            keyList.addAll(redisUtil.getKey(RedisCode.getUserLoginToken(TOKEN_LIKE + userId)));
        }
        redisUtil.batchDel(keyList);
    }

    @Override
    public void removeLoginStatus(Integer userId, LoginEnum loginEnum) {
        String loginStatusKey = RedisCode.getUserLoginStatus(userId, loginEnum.getCode());
        redisUtil.set(loginStatusKey, LOGIN_OFFLINE);
    }

    @Override
    public void remove(String token) {
        //todo
    }

    @Override
    public void update(Integer userId, String currentToken, TokenEntity tokenEntity) {
        Set<String> tokenKeys = redisUtil.getKey(RedisCode.getUserLoginToken(TOKEN_LIKE + userId));
        log.info("修改缓存内容{}", JSON.toJSONString(tokenKeys));

        String currentTokenKey = RedisCode.getUserLoginToken(currentToken);

        //remove
        for (String tokenKey : tokenKeys) {
            if (!tokenKey.equals(currentTokenKey)) {
                redisUtil.remove(tokenKey);
            }
        }

        //update
        if (Objects.nonNull(tokenEntity)) {
            redisUtil.set(currentTokenKey, tokenEntity, redisUtil.getExpire(currentTokenKey, TIME_UNIT), TIME_UNIT);
        }
    }

    @Override
    public TokenEntity getInfo(String token) {
        return redisUtil.get(RedisCode.getUserLoginToken(token));
    }

    @Override
    public TokenEntity getAdminInfo(String token) {
        return redisUtil.get(RedisCode.getAdminToken(token));
    }

    @Override
    public TokenEntity getTokenfo(String token) {
        TokenEntity tokenEntity = getInfo(token);
        return Objects.isNull(tokenEntity) ? getAdminInfo(token) : tokenEntity;
    }

    @Override
    public boolean isLogin(String token) {
        TokenEntity tokenEntity = getInfo(token);
        return Objects.nonNull(tokenEntity);
    }

    @Override
    public boolean isLoginStatus(Integer userId, LoginEnum loginEnum) {
        String loginStatusKey = RedisCode.getUserLoginStatus(userId, loginEnum.getCode());
        return LOGIN_ONLINE.equals(redisUtil.get(loginStatusKey));
    }

    @Override
    public boolean hasLoginStatus(Integer userId, LoginEnum loginEnum) {
        String loginStatusKey = RedisCode.getUserLoginStatus(userId, loginEnum.getCode());
        return redisUtil.hasKey(loginStatusKey);
    }
}
